package shape;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Color;
import android.util.Log;

import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import car.bkrc.com.car2018.FirstActivity;
import util.opencvUtils;
//import android.graphics.Rect;

public class shape {

    private static Bitmap img;
    private static int imgWidth;
    private static int imgHeight;
    private static int[] imgPixels;

    public static Mat mRgb;
    public static Mat mHsv;
    public static Mat imgMat2;
    public static Mat mask;

    private static void setImgInfo(Bitmap image) {
        img = image;
        imgWidth = img.getWidth();
        imgHeight = img.getHeight();
        imgPixels = new int[imgWidth * imgHeight];
        img.getPixels(imgPixels, 0, imgWidth, 0, 0, imgWidth, imgHeight);
    }

    /**
     * 将图片化成灰度图
     *
     * @param img
     * @return
     */
    public static Bitmap converyToGrayImg(Bitmap img) {

        setImgInfo(img);

        return getGrayImg();
    }

    /**
     * 对图像进行预处理
     *
     * @param img
     * @return
     */
    public static Bitmap doPretreatment(Bitmap img) {

        setImgInfo(img);
        mRgb = opencvUtils.bitmapToMat(img);
        mHsv = new Mat(img.getHeight(), img.getWidth(), CvType.CV_8UC3, new Scalar(0));
        mask = new Mat(img.getHeight(), img.getWidth(), CvType.CV_8UC1);
        Imgproc.cvtColor(mRgb, mHsv, Imgproc.COLOR_RGB2HSV);
        Core.inRange(mHsv, new Scalar(100, 90, 90), new Scalar(120, 255, 255), mask);

        opencvUtils.toDilate(mask, 4, 4, 1);
        opencvUtils.toErode(mask, 4, 4, 1);
        //Core.bitwise_and(mResult,);
        List<MatOfPoint> contours = opencvUtils.findContoursList(mask);
        Rect rect = new Rect(0, 0, 0, 0);
        for (int i = 0; i < contours.size(); i++) {
            Rect rect1 = Imgproc.boundingRect(contours.get(i));
            //Log.i("______________1", ""+Imgproc.contourArea(contours.get(i)));
            if (Imgproc.contourArea(contours.get(i)) > 0.01 * imgWidth * imgHeight) {
                float K = (float) rect1.width / rect1.height;
                Log.i("______________1", "" + Imgproc.contourArea(contours.get(i)));
                Log.i("______________2", "" + K);
                if (K > 2.9 && K < 3.8) {
                    imgMat2 = new Mat(mRgb, new Rect((int) (rect1.x + 0.19 * rect1.width), (int) (rect1.y + 0.1 * rect1.height), (int) (0.8 * rect1.width), (int) (0.8 * rect1.height)));
                    Imgproc.cvtColor(imgMat2, imgMat2, Imgproc.COLOR_BGR2GRAY);
                    Imgproc.GaussianBlur(imgMat2, imgMat2, new Size(5, 5), 0);
//					int[] p=new int[2];
//					getMinMaxGrayValue(p,imgMat2);
//					// 计算迭代法阈值
//					int T1 = getIterationHresholdValue(p[0], p[1],imgMat2);
                    opencvUtils.toBinaryMat(imgMat2, 190, 255);
                    int jumpCount1 = 0;
                    byte[] data = new byte[imgMat2.cols()];
                    imgMat2.get(imgMat2.rows() / 3, 0, data);
                    for (int j = 0; j < imgMat2.cols() - 1; j++) {
                        if (data[j] != data[j + 1])
                            jumpCount1++;
                    }
                    Log.i("______________3", "" + jumpCount1);
                    if (jumpCount1 > 10 && jumpCount1 < 35) {

                        opencvUtils.toErode(imgMat2, 2, 2, 1);
                        opencvUtils.toDilate(imgMat2, 2, 2, 1);
                        imgMat2 = clearLiuDing(imgMat2);
                        //imgMat2=clean(imgMat2);
                        Bitmap result = matToBitmap(imgMat2);
                        shape.img = null;
//						opencvUtils.mRgb=null;
//						opencvUtils.mHsv=null;
//						opencvUtils.mask=null;
//						opencvUtils.imgMat2=null;
                        imgPixels = null;
                        return result;
                        //rect = rect1;
                        //Log.i("______________3", ""+rect);
                        //Imgproc.rectangle(mRgb, new Point(rect1.x, rect1.y), new Point(rect1.x + rect1.width, rect1.y + rect1.height), new Scalar(0, 255, 0), 1);
                        //Imgproc.putText(mRgb, "" + i, new Point(rect1.x, rect1.y), Imgproc.FONT_HERSHEY_SIMPLEX, 1, new Scalar(0, 0, 255), 2);
                        //break;
                    }
                }
            }
        }
        //cv2.saveMatAsPngFile(mRgb,"mRgb");
        //Log.i("______________4", ""+rect);
        //Mat imgMat=new Mat(100,100,CvType.CV_8UC3);
        //if(rect.width!=0)
        //imgMat = new Mat (mRgb,rect);//new Rect((int)(rect.x+0.01*rect.width),(int)(rect.y+0.01*rect.height),(int)(0.98*rect.width),(int)(0.85*rect.height)));
        //Imgproc.cvtColor(mRgb, mask, Imgproc.COLOR_RGB2GRAY);
//		for(int i=0;i<rect.height;i++)
//			for(int j=0;j<rect.width;j++)
//				imgMat.put(i,j,mask.get(i+rect.y,j+rect.x));


        //List<MatOfPoint> contours2= cv2.findContoursList(mGray);
        //Rect rect2;
//		for(int i=0;i<contours2.size();i++) {
//			rect2 = Imgproc.boundingRect(contours2.get(i));
//			//Log.i("______________1", ""+Imgproc.contourArea(contours.get(i)));
//			if (rect2.height<20||rect2.width<20) {
//				Log.i("______________1", ""+Imgproc.contourArea(contours2.get(i)));
//				Imgproc.drawContours(mGray,contours2,i, Scalar.all(128),1,Imgproc.LINE_8);
//			}
//		}
        //mGray=clearLiuDing(mGray);
        //cv2.toDilate(mGray,2,2,1);
        //cv2.toErode(mGray,2,2,1);
        //int[] p = new int[2];
        //int maxGrayValue = 0, minGrayValue = 255;
        // 计算最大及最小灰度值
        //getMinMaxGrayValue(p);
        //minGrayValue = p[0];
        //maxGrayValue = p[1];
        // 计算迭代法阈值
        //int T1 = getIterationHresholdValue(minGrayValue, maxGrayValue);
        // // 计算大津法阈值
        // int T2 = getOtsuHresholdValue(minGrayValue, maxGrayValue);
        // // 计算最大熵法阈值
        // int T3 = getMaxEntropytHresholdValue(minGrayValue, maxGrayValue);
        // int[] T = { T1, T2, T3 };
        //
        // Bitmap result = selectBinarization(T);


        //img.recycle();
        //img = null;
        return img;
    }

    public static ArrayList shape(Bitmap img) {
        ArrayList<ColorShapeInfo> resultList = new ArrayList<>();
        Mat image = opencvUtils.bitmapToMat(img);
        opencvUtils.toGaussUnClearMat(image, 5, 5, 0);
        Imgproc.cvtColor(image, image, Imgproc.COLOR_RGB2HSV);
        Mat image2 = new Mat(image.rows(), image.cols(), CvType.CV_8UC1, new Scalar(0));
        Mat image1 = opencvUtils.cloneMat(image2);

        Core.inRange(image, new Scalar(48, 60, 60), new Scalar(78, 255, 255), image1);//绿色
        Core.add(image2, image1, image2);
        Core.inRange(image, new Scalar(0, 60, 60), new Scalar(9, 255, 255), image1);//红色
        Core.add(image2, image1, image2);
        Core.inRange(image, new Scalar(170, 60, 60), new Scalar(180, 255, 255), image1);//红色
        Core.add(image2, image1, image2);
        Core.inRange(image, new Scalar(105, 60, 60), new Scalar(130, 255, 255), image1);//蓝色
        Core.add(image2, image1, image2);
        Core.inRange(image, new Scalar(80, 60, 60), new Scalar(104, 255, 255), image1);//青色
        Core.add(image2, image1, image2);
        Core.inRange(image, new Scalar(0, 0, 0), new Scalar(180, 255, 55), image1);//黑色
        Core.add(image2, image1, image2);
        image1.release();//释放image1
        opencvUtils.coverBackGroundToBlack(image2);// 背景变黑
        opencvUtils.toErode(image2, 5, 5, 1);// 腐蚀
        opencvUtils.toErode(image2, 5, 5, 1);// 腐蚀
        opencvUtils.toDilate(image2, 5, 5, 1);// 膨胀

        Mat mat1 = new Mat(image.rows(), image.cols(), CvType.CV_8UC3, new Scalar(0, 0, 0));// 黑色背景
        List<MatOfPoint> contoursList = opencvUtils.findContoursList2(image2);// 找到轮廓
        image2.release();//释放image2
        for (int i = 0; i < contoursList.size() && contoursList.size() <= 9; i++) {// 处理单个轮廓
            Mat mat = new Mat(image.rows(), image.cols(), CvType.CV_8UC1, new Scalar(0, 0, 0));// 黑色背景
            double len = Imgproc.arcLength(new MatOfPoint2f(contoursList.get(i).toArray()), true);
            MatOfPoint2f point2f = new MatOfPoint2f();
            Imgproc.approxPolyDP(new MatOfPoint2f(contoursList.get(i).toArray()), point2f, 0.02 * len, true);
            List<MatOfPoint> points = new ArrayList<MatOfPoint>();
            points.add(new MatOfPoint(point2f.toArray()));
            Imgproc.drawContours(mat, points, 0, new Scalar(255, 255, 255), Imgproc.FILLED);// 白色描边
            Imgproc.drawContours(mat1, points, 0, new Scalar(0, 255, 0), 1);// 白色描边

            Point[] checkedPoints = opencvUtils.checkPoint(point2f.toArray());// 清除同一条直线上的点
            Point point = opencvUtils.getCenterPoint(mat);
            resultList.add(new ColorShapeInfo(opencvUtils.findColor(image, point), opencvUtils.findShape(checkedPoints)));
            for (int t = 0; t < checkedPoints.length; t++)
                Imgproc.circle(mat1, checkedPoints[t], 2, new Scalar(255, 0, 0), 3);
            opencvUtils.drawCircleByPoint(mat1, point);
            opencvUtils.printWordsOnMat(mat1, point, Integer.toString(i));
            mat.release();//释放mat
        }
        image.release();//释放image
        mat1.release();//释放mat1
        if (resultList.size() != 0) {
            FirstActivity.Connect_Transport.result_shape = Arrays.toString(resultList.toArray());
            Log.d("CvResoult___________", FirstActivity.Connect_Transport.result_shape);
            return resultList;
        } else {
            Log.d("CvResoult___________", "识别失败");
            return null;
        }
    }

    public static class ColorShapeInfo {
        public String shape;
        public String color;

        public ColorShapeInfo(String shape1, String color1) {
            shape = shape1;
            color = color1;
        }

        public String getShape() {
            return shape;
        }

        public String getColor() {
            return color;
        }

        @Override
        public String toString() {
            return "(" + shape + "," + color + ")";
        }
    }

    /**
     * 获取当前图片的灰度图
     *
     * @param
     */
    private static Bitmap getGrayImg() {

        int alpha = 0xFF << 24;
        for (int i = 0; i < imgHeight; i++) {
            for (int j = 0; j < imgWidth; j++) {
                int grey = imgPixels[imgWidth * i + j];

                int red = ((grey & 0x00FF0000) >> 16);
                int green = ((grey & 0x0000FF00) >> 8);
                int blue = (grey & 0x000000FF);

                grey = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11);
                grey = alpha | (grey << 16) | (grey << 8) | grey;
                imgPixels[imgWidth * i + j] = grey;
            }
        }
        Bitmap result = Bitmap
                .createBitmap(imgWidth, imgHeight, Config.RGB_565);
        result.setPixels(imgPixels, 0, imgWidth, 0, 0, imgWidth, imgHeight);
        return result;
    }

    private static int getGray(int argb) {
        int alpha = 0xFF << 24;
        int red = ((argb & 0x00FF0000) >> 16);
        int green = ((argb & 0x0000FF00) >> 8);
        int blue = (argb & 0x000000FF);
        int grey;
        grey = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11);
        grey = alpha | (grey << 16) | (grey << 8) | grey;
        return grey;
    }

    // 利用迭代法计算阈值
    private static int getIterationHresholdValue(int minGrayValue,
                                                 int maxGrayValue, Mat imgMat2) {
        int T1;
        int T2 = (maxGrayValue + minGrayValue) / 2;
        byte[] data = new byte[imgMat2.cols()];
        do {
            T1 = T2;
            double s = 0, l = 0, cs = 0, cl = 0;
            for (int i = 0; i < imgMat2.rows(); i++) {
                imgMat2.get(i, 0, data);
                for (int j = 0; j < imgMat2.cols(); j++) {
                    if (data[j] < T1) {
                        s += data[j];
                        cs++;
                    }
                    if (data[j] > T1) {
                        l += data[j];
                        cl++;
                    }
                }
            }
            T2 = (int) (s / cs + l / cl) / 2;
        } while (T1 != T2);
        return T1;
    }

    /*
     * 用大津法计算阈值T 大津法又称为最大类间方差法，由大津在1979年提出，选取使类间方差最
     * 大的灰度级作为分割阈值，方差值越大，说明图像两部分差别越大。
     */
    private static int getOtsuHresholdValue(int minGrayValue, int maxGrayValue) {
        int T = 0;
        double U = 0, U0 = 0, U1 = 0;
        double G = 0;
        for (int i = minGrayValue; i <= maxGrayValue; i++) {
            double s = 0, l = 0, cs = 0, cl = 0;
            for (int j = 0; j < imgHeight - 1; j++) {
                for (int k = 0; k < imgWidth - 1; k++) {
                    int gray = imgPixels[imgWidth * j + k];
                    if (gray < i) {
                        s += gray;
                        cs++;
                    }
                    if (gray > i) {
                        l += gray;
                        cl++;
                    }
                }
            }
            U0 = s / cs;
            U1 = l / cl;
            U = (s + l) / (cs + cl);
            double g = (cs / (cs + cl)) * (U0 - U) * (U0 - U)
                    + (cl / (cl + cs)) * (U1 - U) * (U1 - U);
            if (g > G) {
                T = i;
                G = g;
            }
        }
        return T;
    }

    // 采用一维最大熵法计算阈值
    private static int getMaxEntropytHresholdValue(int minGrayValue,
                                                   int maxGrayValue) {
        int T3 = minGrayValue, sum = 0;
        double E = 0, Ht = 0, Hl = 0;
        int[] p = new int[maxGrayValue - minGrayValue + 1];
        for (int i = minGrayValue; i <= maxGrayValue; i++) {
            for (int j = 0; j < p.length; j++) {
                p[j] = 0;
            }
            sum = 0;
            for (int j = 0; j < imgHeight - 1; j++) {
                for (int k = 0; k < imgWidth - 1; k++) {
                    int gray = imgPixels[imgWidth * j + k];
                    p[gray - minGrayValue] += 1;
                    sum++;
                }
            }

            double pt = 0;
            int offset = maxGrayValue - i;
            for (int j = 0; j < p.length - offset; j++) {
                if (p[j] != 0) {
                    Ht += (p[j] * (Math.log(p[j]) - Math.log(sum))) / sum;
                    pt += p[j];
                }
            }
            for (int j = p.length - offset; j < maxGrayValue - minGrayValue + 1; j++) {
                if (p[j] != 0) {
                    Ht += (p[j] * (Math.log(p[j]) - Math.log(sum))) / sum;
                }
            }
            pt /= sum;
            double e = Math.log(pt * (1 - pt)) - (Ht / pt) - Hl / (1 - pt);

            if (E < e) {
                E = e;
                T3 = i;
            }
        }
        return T3;
    }

    // 针对单个阈值二值化图片
    private static Bitmap binarization(int T) {
        // 用阈值T1对图像进行二值化
        for (int i = 0; i < imgHeight; i++) {
            for (int j = 0; j < imgWidth; j++) {
                int gray = imgPixels[i * imgWidth + j];
                if (gray < T) {
                    // 小于阈值设为白色
                    imgPixels[i * imgWidth + j] = Color.rgb(0, 0, 0);
                } else {
                    // 大于阈值设为黑色
                    imgPixels[i * imgWidth + j] = Color.rgb(255, 255, 255);
                }
            }
        }

        Bitmap result = Bitmap
                .createBitmap(imgWidth, imgHeight, Config.RGB_565);
        result.setPixels(imgPixels, 0, imgWidth, 0, 0, imgWidth, imgHeight);

        return result;
    }

    // 计算最大最小灰度,保存在数组中
    private static void getMinMaxGrayValue(int[] p, Mat img) {
        int minGrayValue = 255;
        int maxGrayValue = 0;
        byte[] data = new byte[img.cols()];
        for (int i = 0; i < img.rows() - 1; i++) {
            img.get(i, 0, data);
            for (int j = 0; j < img.cols() - 1; j++) {
                if (data[j] < minGrayValue)
                    minGrayValue = data[j];
                if (data[j] > maxGrayValue)
                    maxGrayValue = data[j];
            }
        }
        p[0] = minGrayValue;
        p[1] = maxGrayValue;
    }

    /**
     * 由3个阈值投票二值化图片
     *
     * @param T 三种方法获得的阈值
     * @return 二值化的图片
     */
    private static Bitmap selectBinarization(int[] T) {
        for (int i = 0; i < imgHeight; i++) {
            for (int j = 0; j < imgWidth; j++) {
                int gray = imgPixels[i * imgWidth + j];
                if (gray < T[0] && gray < T[1] || gray < T[0] && gray < T[2]
                        || gray < T[1] && gray < T[2]) {
                    imgPixels[i * imgWidth + j] = Color.rgb(0, 0, 0);
                } else {
                    imgPixels[i * imgWidth + j] = Color.rgb(255, 255, 255);
                }
            }
        }

        Bitmap result = Bitmap
                .createBitmap(imgWidth, imgHeight, Config.RGB_565);
        result.setPixels(imgPixels, 0, imgWidth, 0, 0, imgWidth, imgHeight);

        return result;
    }

    // 计算像素点（x,y)周围像素点的中值
    private static int getCenterValue(Bitmap img, int x, int y) {
        int[] pix = new int[9];

        int w = img.getHeight() - 1;
        int h = img.getWidth() - 1;
        //
        if (x > 0 && y > 0)
            pix[0] = getGray(img.getPixel(x - 1, y - 1));
        if (y > 0)
            pix[1] = getGray(img.getPixel(x, y - 1));
        if (x < h && y > 0)
            pix[2] = getGray(img.getPixel(x + 1, y - 1));
        if (x > 0)
            pix[3] = getGray(img.getPixel(x - 1, y));
        pix[4] = getGray(img.getPixel(x, y));
        if (x < h)
            pix[5] = getGray(img.getPixel(x + 1, y));
        if (x > 0 && y < w)
            pix[6] = getGray(img.getPixel(x - 1, y + 1));
        if (y < w)
            pix[7] = getGray(img.getPixel(x, y + 1));
        if (x < h && y < w)
            pix[8] = getGray(img.getPixel(x + 1, y + 1));

        int max = 0, min = 255;
        for (int i = 0; i < pix.length; i++) {
            if (pix[i] > max)
                max = pix[i];
            if (pix[i] < min)
                min = pix[i];
        }
        int count = 0;
        int i = 0;
        for (i = 0; i < 9; i++) {
            if (pix[i] >= min)
                count++;
            if (count == 5)
                break;
        }
        return pix[i];
    }

    //Mat转Bitmap
    public static Bitmap matToBitmap(Mat mat) {
        Bitmap resultBitmap = null;
        if (mat != null) {
            resultBitmap = Bitmap.createBitmap(mat.cols(), mat.rows(), Config.ARGB_8888);
            if (resultBitmap != null)
                Utils.matToBitmap(mat, resultBitmap);
        }
        return resultBitmap;
    }

    //Bitmap转Mat
    public static Mat bitmapToMat(Bitmap bm) {
        Bitmap bmp32 = bm.copy(Config.RGB_565, true);
        Mat imgMat = new Mat(bm.getHeight(), bm.getWidth(), CvType.CV_8UC2, new Scalar(0));
        Utils.bitmapToMat(bmp32, imgMat);
        return imgMat;
    }

    public static Mat clearLiuDing(Mat img) {
        //final int x = 7;
        int jumpCount;

        //Mat jump = Mat.zeros(1, img.rows(), CV_32F);
        for (int i = 0; i < img.rows(); i++) {
            jumpCount = 0;
            byte[] data = new byte[img.cols()];
            img.get(i, 0, data);
            for (int j = 0; j < img.cols() - 1; j++) {
                if (data[j] != data[j + 1])
                    jumpCount++;
            }
            Log.i("______________5", "" + jumpCount);
            if (jumpCount < 10) {

                for (int k = 0; k < img.cols(); k++) {
                    img.put(i, k, (byte) 0);
                }
            }
        }

        for (int j = 0; j < 0.03 * img.cols(); j++) {
            for (int k = 0; k < img.rows(); k++) {
                img.put(k, j, (byte) 0);
            }
            for (int k = 0; k < img.rows(); k++) {
                img.put(k, img.cols() - j, (byte) 0);
            }
        }
        return img;
    }

    public static Mat clean(Mat img) {
        for (int j = 0; j < 0.03 * img.cols(); j++) {
            for (int k = 0; k < img.rows(); k++) {
                img.put(k, j, (byte) 0);
            }
            for (int k = 0; k < img.rows(); k++) {
                img.put(k, img.cols() - j, (byte) 0);
            }
        }
        for (int j = 0; j < 0.1 * img.rows(); j++) {
            for (int k = 0; k < img.cols(); k++) {
                img.put(j, k, (byte) 0);
            }
            for (int k = 0; k < img.cols(); k++) {
                img.put(img.rows() - j, k, (byte) 0);
            }
        }
        return img;
    }

}
